#include "fs/vfs.h"
#include "assert.h"
#include "error.h"
#include "fs/deffs.h"
#include "fs/inode.h"
#include "lock.h"
#include "mmu.h"
#include "proc.h"
#include "stdio.h"

static spinlock_t bootFSLock;
static inode_t* bootFSNode = NULL;

extern void vfs_deviceListInit(void);

/**
 * @brief allocate memory for fs, and set fs type
 *
 * @param type
 * @return fs_t*
 */
fs_t*
__alloc_fs(uint32_t type) {
    fs_t* fs = kmalloc(sizeof(fs_t));
    if (fs != NULL)
        fs->fs_type = type;
    return fs;
}

/**
 * @brief vfs initialize
 *
 */
void
vfs_init(void) {
    spinlock_init(&bootFSLock, "");
    vfs_deviceListInit();
}

/**
 * @brief lock for boot fs
 *
 */
static inline void
lockBootFS(void) {
    spinlock_acquire(&bootFSLock);
}

/**
 * @brief unlock for boot fs
 *
 */
static inline void
unlockBootFS(void) {
    spinlock_release(&bootFSLock);
}

/**
 * @brief set new fs inode
 *
 * @param node
 */
static void
changeBootFS(inode_t* node) {
    inode_t* old;
    lockBootFS();
    {
        old = bootFSNode;
        bootFSNode = node;
    }
    unlockBootFS();
    if (old != NULL)
        vop_refDec(old);
}

/**
 * @brief 设置文件系统目录位置
 *
 * 注意，此函数中未加锁，实际修改文件系统在changeBootFS中进行
 * 该函数进行了加锁。
 *
 * @param fsName
 * @return int
 */
int
vfs_setBootFS(char* fsName) {
    inode_t* node = NULL;
    if (fsName != NULL) {
        int ret = vfs_chdir(fsName);
        if (ret != 0)
            return ret;
        ret = vfs_getCurrentDir(&node);
        return ret;
    }
    changeBootFS(node);
    return 0;
}

int
vsf_getBootFS(inode_t** node_store) {
    inode_t* node = NULL;
    lockBootFS();
    if (bootFSNode != NULL) {
        node = bootFSNode;
        vop_refInc(bootFSNode);
    }
    unlockBootFS();
    if (node == NULL)
        return -E_NOENTRY;
    *node_store = node;
    return 0;
}